﻿using System;
using System.Net;
using System.Text;
using System.Threading;
using System.Runtime.CompilerServices;

using SimbaRGVMonitor.Common.Net;
using SimbaRGVMonitor.Common.Linq;
using SimbaRGVMonitor.Common.Utils;
using SimbaRGVMonitor.Common.Diagnostics;

namespace SimbaRGVMonitor.Controllers
{
    class MonitorTcpAgent
    {
        public MonitorTcpAgent(string name, IPEndPoint serverPoint)
        {
            InitializeSettings();

            this.name = name;
            this.serverPoint = serverPoint;
            logger = MonitorCenter.Instance.GetLogger(name);
        }

        //====================================================================================================
        //以上是类型构造函数
        //----------------------------------------------------------------------------------------------------
        //以下是类型字段
        //====================================================================================================

        private readonly string name;
        private bool autoConnect = true;
        private readonly MonitorLogger logger;
        private readonly IPEndPoint serverPoint;
        private readonly MonitorTcpClient tcpClient = new MonitorTcpClient();

        //====================================================================================================
        //以上是类型字段
        //----------------------------------------------------------------------------------------------------
        //以下是类型属性
        //====================================================================================================

        public string Name { get { return name; } }
        public bool Connected { get { return tcpClient.Connected; } }
        protected IPEndPoint ServerPoint { get { return serverPoint; } }

        //====================================================================================================
        //以上是类型属性
        //----------------------------------------------------------------------------------------------------
        //以下是类型事件及触发函数
        //====================================================================================================

        public event EventHandler<MonitorTcpAgentMessageReceivedEventArgs> MessageReceived;
        private void OnMessageReceived(DateTime receiveTime, string message)
        {
            var e = new MonitorTcpAgentMessageReceivedEventArgs(receiveTime, message);
            MessageReceived.TriggerEvent(this, e);
        }

        public event EventHandler<MonitorTcpAgentConnectStateChangedEventArgs> ConnectStateChanged;
        private void OnConnectStateChanged(bool connected)
        {
            var e = new MonitorTcpAgentConnectStateChangedEventArgs(connected);
            ConnectStateChanged.TriggerEvent(this, e);
        }

        //====================================================================================================
        //以上是类型事件及触发函数
        //----------------------------------------------------------------------------------------------------
        //以下是初始化设置
        //====================================================================================================

        private void InitializeSettings()
        {
            tcpClient.DataReceived += WhenDataReceived;
            tcpClient.ExceptionCaught += WhenExceptionCaught;
            tcpClient.ConnectStateChanged += WhenConnectStateChanged;
        }

        //====================================================================================================
        //以上是初始化设置
        //----------------------------------------------------------------------------------------------------
        //以下开启及关闭
        //====================================================================================================

        public async void OpenAsync()
        {
            while(true)
            {
                try
                {
                    autoConnect = true;
                    await tcpClient.ConnectAsync(serverPoint);
                    break;
                }
                catch (Exception ex)
                {
                    var reason = ex.GetInnerExceptionMessage();
                    var message = string.Format("TCP[{0}]启动发生错误:{1}", name, reason);
                    logger.Info(message);
                }

                Thread.Sleep(1000);
            }
        }

        public async void CloseAsync()
        {
            try
            {
                autoConnect = false;
                await tcpClient.CloseAsync();
            }
            catch(Exception ex)
            {
                var reason = ex.GetInnerExceptionMessage();
                var message = string.Format("TCP[{0}]关闭发生错误:{1}", name, reason);
                logger.Info(message);
            }
        }

        //====================================================================================================
        //以上是初始化及关闭
        //----------------------------------------------------------------------------------------------------
        //以下是发送TCP数据
        //====================================================================================================

        [MethodImpl(MethodImplOptions.Synchronized)]
        public void SendJsonData(object data)
        {
            var message = SerializeUtil.SerializeToJson(data);
            SendMessage(message);
        }

        private async void SendMessage(string message)
        {
            var bytes = Encoding.UTF8.GetBytes(message);
            try
            {
                if (tcpClient.Connected == false)
                {
                    var reason = "TCP连接未建立或断开，无法发送数据";
                    throw new InvalidOperationException(reason);
                }

                await tcpClient.SendAsync(bytes);
                var logText = string.Format("TCP[{0}]发送数据{1}", name, message);
                logger.Info(logText);
            }
            catch (Exception ex)
            {
                var title = string.Format("TCP[{0}]发送数据发生错误", name);
                logger.Error(title, ex);
            }
        }

        //====================================================================================================
        //以上是发送TCP数据
        //----------------------------------------------------------------------------------------------------
        //以下是TCP事件侦听
        //====================================================================================================

        private void WhenDataReceived(object sender, MonitorTcpClientDataReceivedEventArgs e)
        {
            var receiveTime = e.ReceiveTime;
            var receiveBytes = e.ReceiveBytes;
            try
            {
                var message = Encoding.UTF8.GetString(receiveBytes);
                var logText = string.Format("TCP[{0}]收到消息:{1}", name, message);
                logger.Info(logText);
                OnMessageReceived(receiveTime, message);
            }
            catch(Exception ex)
            {
                var title = string.Format("TCP[{0}]接收消息时发生错误", name);
                logger.Error(title, ex);
            }
        }

        private void WhenExceptionCaught(object sender, MonitorTcpClientExceptionCaughtEventArgs e)
        {
            var ex = e.Ex;
            var title = string.Format("TCP[{0}]发生错误", name);
            logger.Error(title, ex);
        }

        private async void WhenConnectStateChanged(object sender, MonitorTcpClientEventArgs e)
        {
            try
            {
                var logText = string.Format("TCP[{0}]{1}", name, tcpClient.Connected ? "已连接" : "已断开");
                logger.Info(logText);

                var connected = tcpClient.Connected;
                OnConnectStateChanged(connected);

                while (tcpClient.Connected == false && autoConnect)
                {
                    try
                    {
                        await tcpClient.ConnectAsync(serverPoint);
                    }
                    catch(Exception ex)
                    {
                        var reason = ex.GetInnerExceptionMessage();
                        var message = string.Format("TCP[{0}]重连失败:{1}", name, reason);
                        logger.Warn(message);
                    }

                    Thread.Sleep(1000);
                }
            }
            catch (Exception ex)
            {
                var title = string.Format("TCP[{0}]连接状态变更时发生错误", name);
                logger.Error(title, ex);
            }
        }
    }
}
